/*global $,$
$,$A,$H,Prototype,Ajax,Template*/
javascript:(function(){
	"use strict";
	var Lint = {},
		$Lint,
		Mediator; /* jQuery Object of #MecaLint ( == $("#MecaLint"))*/
	
	/* -----------------------
		Initialize
	----------------------- */
	Lint.init = function () {
		/* Show Controller after loading jQuery */
		Lint.loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js", function(){
			Mediator = new Lint.Mediator();			
			Mediator.show();
		});
	};
	
	/* -----------------------
		Mediator
	----------------------- */
	Lint.Mediator = function () {
		var LocalStorageHandler = new Lint.LocalStorageHandler(),
			UIFactory = new Lint.UIFactory(),
			Proofreader = new Lint.Proofreader(),
			ScoreBoard = new Lint.ScoreBoard();
			
		var	self = {};
		/* set raw html source of href.location*/
		self.rawSource = ""; 
		
		self.show = function () {
			UIFactory.showUnderBar();
		};
		
		/* firing on click run */
		self.run = function () {
			LocalStorageHandler.save();
			ScoreBoard.init();
			Proofreader.init();
			UIFactory.logSectionInit();
			Proofreader.proofread(function(){
				UIFactory.showScoreBoard();	
				ScoreBoard.sort("dsc");
			});
		};
		
		/* update scoreboard */
		self.updateScore = function (result_set1, result_set2) {
			ScoreBoard.updateScore(result_set1, result_set2);
		};
		
		self.sortScoreBoard = function ($tr) {
			ScoreBoard.sort($tr);
		};
		
		self.mark = function (marker, logic_id) {
			Proofreader.mark(marker, logic_id);
		};
		
		self.updateLogRow = function (item) {
			UIFactory.updateLogRow(item);
		};
		
		return self;
	}; /* - - - / Mediator - - - */

	/* -----------------------
		UIFactory
	----------------------- */
	Lint.UIFactory = function () {
		/* dependency */
		var Util = new Lint.Util(),
			LocalStorageHandler = new Lint.LocalStorageHandler();
			
		var self = {};
		
		self.showUnderBar = function () {
			var wrapper = createWrapper();
			
			wrapper
				.append(createBtnRun())
				.append(createSettingBox())
				.append(createBtnOpen())
				.append(createTotalTxt())
				.append(createLogSection());
			$("body").prepend(wrapper);
			
			$Lint = $("#MecaLint");
			$Lint.find(".btnMecaLint").hover(function(){
				$(this).css("opacity", "0.7");
			},function(){
				$(this).css("opacity", "1");
			});
			$Lint.animate({"top": Util.getBrowserHeight() - 30 + "px"}, 300);
			$(window).resize(setUnderBarPosition);
			LocalStorageHandler.load();
		};
		
		function setUnderBarPosition () {
			if ($Lint.css("top") === "0px") {
				$Lint.css({
					"height": Util.getBrowserHeight() + "px"
				});
			} else {
				$Lint.css({
					"height": "40px",
					"top": Util.getBrowserHeight() - 30 + "px"
				});	
			}
		}
		
		self.logSectionInit = function () {
			$(".btnRunEvaluate").val("…評価中");
			$Lint.find(".logSection *").remove();
			
			var box = createLogBox(),
				ttl = createLogTitle(),
				dtbl = createDetailTable();
			box.addClass("boxLogProf");
			ttl.find("td:first").append("田村佳也の「お前のコード」に一言物申す");
			dtbl.append(createDetailTableRowProf(true));
			box.append(ttl).append(dtbl);
			$Lint.find(".logSection").append(box);
		};		
		
		self.updateLogRow = function (args) {
			if (args.cmd_type === "add") {
				addProfRow(args);
			} else if (args.cmd_type === "update") {
				updateProfRow(args);
			}
		};
		
		/* private methods (CreateDOM) */
		
		function createWrapper () {
			var wrapper = $("<div />");
			wrapper.attr("id", "MecaLint");
			wrapper.css({
				"position"　			: "fixed",
				"z-index"　			: "9999999",
				"left"　				: "0",
				"top"　				: Util.getBrowserHeight() + "px",
				"width"				: "100%",
				"min-height"		: "50px",
				"background-color"	: "#ddd",
				"background-image"	: "-webkit-gradient(linear, left top, left bottom,color-stop(0, rgb(247, 247, 247)),color-stop(0.7, rgb(204, 204, 204)))",
				"opacity"			: "0.98",
				"-webkit-box-shadow": "0px -0.3px 6px rgb(51, 51, 51)",
				"-moz-box-shadow"	: "0px -0.3px 6px rgb(71, 71, 71)",
				"-ms-box-shadow"	: "0px -0.3px 6px rgb(71, 71, 71)",
				"box-shadow"		: "0px -0.3px 6px rgb(71, 71, 71)",
				"text-shadow"		: "1px 1px 0px rgb(255, 255, 255)",
				"font-size"			: "12px",
				"color"				: "#222",
				"font-family"		: "メイリオ, Meiryo, ヒラギノ角ゴ Pro W3, Hiragino Kaku Gothic Pro, Verdana, ＭＳ　Ｐゴシック, Lucida Grande, sans-serif !important"
			});
			return wrapper;
		}
		
		function createLogSection () {
			var section = $("<div />");
			section.attr("class", "logSection");
			section.css({
				"width"		: "95%",
				"clear"		: "both",
				"margin"	: "20px auto 0 auto",
				"display"	: "none"
			});
			return section;
		}
		
		function getBtnStyle () {
			return {
				"display"			: "block",
				"float"				: "left",
				"min-width"			: "120px",
				"border"			: "1px solid #ccc",
				"background-color"	: "#fff",
				"margin"			: "3px 0 0 4px",
				"padding"			: "0 10px",
				"cursor"			: "pointer",
				"font-family"		: "メイリオ"
			};
		}
		
		function createBtnRun() {
			var btn = $("<input />");
			btn.attr({
				"class"	: "btnMecaLint btnRunEvaluate",
				"type"	: "button",
				"value"	: "検収開始",
				"width" : 200
			});
			btn.css(getBtnStyle());
			btn.click(Mediator.run);
			return btn;
		}
		
		function createBtnOpen() {
			var btn = $("<input />");
			btn.attr({
				"class"	: "btnMecaLint btnToggle",
				"type"	: "button",
				"value"	: "詳細"
			});
			btn.css(getBtnStyle());
			btn.css({
				"float"			: "right",
				"width"			: "60px",
				"margin-right"	: "4px",
				"display" 		: "none"
			});
			btn.click(toggleUnderBar);
			return btn;
		}
		
		function toggleUnderBar () {
			if ($Lint.css("top") === "0px") {
				$Lint.animate({
					height: "40px",
					top: Util.getBrowserHeight() - 30 + "px"
				}, 500, function () {				
					$Lint.css({"overflow-y": "hidden"});
					$Lint.find(".btnToggle").val("詳細");
					$Lint.find(".logSection").css("display", "none");
				});
			} else {
				self.showScoreBoard();
			}
		}
		
		self.showScoreBoard = function () {
			$Lint.find(".logSection").css("display", "block");
			$Lint.animate({
				height: Util.getBrowserHeight() + 20 + "px",
				top: "0"
			}, 500, function () {
				$Lint.css({"overflow-y": "scroll"});
				$Lint.find(".btnToggle").css("display", "block").val("閉じる");
				$Lint.find(".btnRunEvaluate").val("再検収");
			});
		};
		
		function createSettingBox() {
			var box = $("<div/>");
			box.css({
				"float": "left",
				"padding-top": "6px"
			});
			
			var label1 = $("<label></label>"),
				input1 = $("<input />");
			input1.attr({
				"type"		: "radio",
				"class"		: "MecaLintSet",
				"name"		: "MecaLintSet",
				"value"		: "pc",
				"style"		: "width:10px;height:10px;",
				"checked"	: "checked"
			});
			box.append(label1.append(input1).append("PC"));
			
			var label2 = $("<label></label>"),
				input2 = $("<input />");
			input2.attr({
				"type"		: "radio",
				"class"		: "MecaLintSet",
				"name"		: "MecaLintSet",
				"value"		: "sp",
				"style"		: "width:10px;height:10px;"
			});
			box.append(label2.append(input2).append("スマホ"));
			
			var label3 = $("<label></label>"),
				input3 = $("<input />");
			input3.attr({
				"type"	: "radio",
				"class"	: "MecaLintSet",
				"name"	: "MecaLintSet",
				"value"	: "m",
				"style"	: "width:10px;height:10px;"
			});
			box.append(label3.append(input3).append("ガラケー"));
			
			var label4 = $("<label></label>"),
				input4 = $("<input />");
			input4.attr({
				"type"		: "checkbox",
				"id"		: "MecaLintSetIE6",
				"name"		: "MecaLintSetIE6",
				"value"		: "true",
				"style"		: "width:10px;height:10px;",
				"checked"	: ""
			});
			box.append(label4.append(input4).append("IE6対応"));

			var label5 = $("<label></label>"),
				input5 = $("<input />");
			input5.attr({
				"type"		: "checkbox",
				"id"		: "MecaLintSetForStudent",
				"name"		: "MecaLintSetForStudent",
				"value"		: "true",
				"style"		: "width:10px;height:10px;",
				"checked"	: ""
			});
			box.append(label5.append(input5).append("学習者向けロジックを含む"));
			
			box.find("input[name='MecaLintSet']:radio").change(function(){
				var val = $(this).val();
				if (val === "pc") {
					$("#MecaLintSetIE6").attr("disabled", "");
				} else {
					$("#MecaLintSetIE6").attr("disabled", "disabled");
				}  
			});
			
			return box;
		}
		
		
		function createTotalTxt() {
			var txt = $("<div />");
			txt.attr("class", "txtTotal");
			txt.css({
				"float"			: "right",
				"min-width"		: "200px",
				"height"		: "20px",
				"font-size"		: "14px",
				"margin"		: "7px 5px 0 0",
				"line-height"	: "1em",
				"color"			: "#222",
				"text-align"	: "right"
			});
			return txt;
		}
		
		function createLogBox () {
			var box = $("<div />");
			box.css({
				"width"				: "100%",
				"min-height"		: "170px",
				"float"				: "left",
				"clear"				: "both",
				"background-color"	: "#fff",
				"border"			: "2px solid #555",
				"margin"			: "10px 0 10px 0",
				"padding"			: "0 0 20px 0"
			});
			return box;
		}
		
		function createLogTitle () {
			var tbl = $("<table></table>");
			tbl.css({
				"width"			: "100%",
				"font-size"		: "22px",
				"clear"			: "both",
				"padding"		: "7px",
				"font-weight"	: "bold",
				"border-bottom"	: "3px dotted #bbb"
			});
			tbl.append("<tr><td></td><td></td></tr>");
			tbl.find("td:first").css({"text-align": "left", "width": "50%"});
			tbl.find("td:last").css({"text-align": "right", "width": "50%"});
			return tbl;
		}
		
		function createDetailTable () {
			var tbl = $("<table></table>");
			tbl.attr({
				"border"		: "1",
				"cellspacing"	: "0",
				"class"			: "tblDetail"
			});
			tbl.css({
				"width"				: "98%",
				"clear"				: "both",
				"margin"			: "20px auto 0 auto",
				"border-collapse"	: "collapse"
			});
			return tbl;
		}
		
		
		function createDetailTableRowProf (for_column_header) {
			var $tr = $("<tr></tr>");
			$tr.append("<td>重要度</td>")
				.append("<td>タイトル</td>")
				.append("<td>IE6固有</td>")
				.append("<td>コメント</td>")
				.append("<td>参考</td>")
				.append('<td class="colNum">減点</td>')
				.append('<td class="colNum">箇所</td>')
				.append('<td class="colNum">小計</td>')
				.find("td").css({
					"height" 			: "25px",
					"text-align" 		: "center",
					"background-color" 	: "#ddd",
					"font-size" 		: "14px",
					"padding" 			: "3px"
				});
			
			/* setting for only column header  */
			if (for_column_header === true) {
				setEventOnColumnHeader($tr);
			}
			$tr.find("td:eq(2)").css({ "width": "34px" });
			$tr.find("td:eq(5), td:eq(6), td:eq(7)").css({ "width": "50px" });
			return $tr;
		}
		
		function setEventOnColumnHeader ($tr) {
			var $td;
			$tr.find("td").each(function(){
				$td = $(this); 
				$td.hover(function(){
					$(this).css("background-color", "#ccc");
				},function(){
					$(this).css("background-color", "#ddd");
				});
				$td.mousedown(function(){
					$(this).css("background-color", "#bbb");
				});
				$td.mouseup(function(){
					$(this).css("background-color", "#ddd");
				});
				$td.click(function(){
					Mediator.sortScoreBoard($(this));
				});
			}).css("cursor", "pointer");
		}
		
		
		function addProfRow (data) {
			var $tr = createDetailTableRowProf();
			$tr.addClass("row" + data.id);
			
			$tr = setProfRow($tr, data);
			$Lint.find(".boxLogProf table:last").append($tr);
		}
		
		function updateProfRow (data) {
			var $tr = $Lint.find(".boxLogProf table:last .row" + data.id);
			setProfRow($tr, data);
		}
		
		function setProfRow ($tr, data) {
			
			var for_ie6 = (data.for_ie6)? "○": "-",
				score = parseInt(data.score, 10);
			$tr.find("td:eq(0)").text(data.rank);
			$tr.find("td:eq(1)").text(data.title);
			$tr.find("td:eq(2)").text(for_ie6);
			$tr.find("td:eq(3)").text(data.desc);
			$tr.find("td:eq(4)").text("");
			for (var i = 0, l = data.ref.length; i < l; i++) {
				var a = $("<a></a>");
				a.attr({
					"href": data.ref[i].url,
					"target": "_blank"
				});
				a.append(data.ref[i].url);
				$tr.find("td:eq(4)").append(data.ref[i].title + "<br />").append(a);
			}
			$tr.find("td:eq(5)").text(score + Lint.Config.Unit);
			if (data.cnt < 100) {
				$tr.find("td:eq(6)").text(data.cnt + "箇所");
			} else {
				$tr.find("td:eq(6)").text("100箇所以上");
			}
			$tr.find("td:eq(7)").text(data.cnt * score + Lint.Config.Unit);
			$tr.find("td").css({
				"text-align" 		: "left",
				"background-color" 	: "#fff",
				"font-size" 		: "12px"
			});
			$tr.find("td:eq(0), td:eq(2), td:eq(5), td:eq(6), td:eq(7)").css("text-align", "center");
			$tr.find("td:eq(1)").css("min-width", "200px");
			return $tr;
		}
		
		
		return self;
	}; /* - - - / UIFactory - - - */
	
	
	/* -----------------------
		ScoreBoard
	----------------------- */
	
	Lint.ScoreBoard = function () {
		/* dependency */
		var SyntaxManager = Lint.SyntaxManager;
			
		var	self = {},
			profResultSet = {};
			
		self.init = function () {
			profResultSet = {};
		};
		
		self.updateScore = function (evl_result_set, prf_result_set) {
			/* set latest data */
			if (prf_result_set !== null) {
				profResultSet = prf_result_set;
			}
			/* update */
			updateTotalizedScore();
			updateResultRows();
		};
		
		self.sort = function (args) {
			var $td = (typeof args === "object") ? args : $Lint.find(".tblDetail:first tr:first td:first"),
				order = (typeof args === "string") ? args : undefined ;		
			if ($td.hasClass("sortAsc")) {
				clearClass();
				$td.addClass("sortDsc");
				sort($td, order || "dsc");
			} else {
				clearClass();
				$td.addClass("sortAsc");
				sort($td, order || "asc");
			}
		};
		
		function clearClass () {
			$Lint.find(".tblDetail:first tr:first td").each(function(){
				$Lint.find(".tblDetail:first tr:first td").removeClass("sortAsc").removeClass("sortDsc");
			});
		}
		function sort ($td, order) {
			var td_list = [];
			$Lint.find(".tblDetail:first tr:gt(0)").each(function(){
				var index = $td.parent().find("td").index($td.get(0)),
					val = $(this).find("td:eq(" + index + ")").text();
				/* for column.colNum, change val from string to number */
				if ($td.hasClass("colNum")) {
					val = parseInt(val, 10);
				}
			    td_list.push({"val":val, "instance":$(this)});
			});
			sortHashArray("val", td_list, order);
			
			$Lint.find(".tblDetail:first tr:gt(0)").remove();
			for (var i = 0, l = td_list.length; i < l; i++) {
				$Lint.find(".tblDetail:first").append(td_list[i].instance);
			}
			setRowToggleEvent();
		}
		/* sort hash array */
		function sortHashArray(key, array, order){
			if (order === "asc") {
				array.sort(function(b1, b2){return b1[key] > b2[key] ? 1 : -1;});
			} else {
				array.sort(function(b1, b2){return b1[key] < b2[key] ? 1 : -1;});
			}
		}
		
		function updateTotalizedScore () {
			var prf_score 		= parseInt(profResultSet.score, 10) || 0,
				prf_data 		= profResultSet.checked_data || {},
				prf_score_calc 	= Lint.Config.MaxPoint + prf_score,
				prf_lbl 		= "ランク" + rank(prf_score_calc) + " " + prf_score_calc +　Lint.Config.Unit,
				total_txt 		= "検収：" +　prf_lbl;
			
			$Lint.find(".txtTotal").text(total_txt);
			var $span = $("<span></span>").css({"font-size":"11px", "color":"#888", "font-weight":"normal"});
			$Lint.find(".boxLogProf table:first td:last").text(prf_lbl);
			$Lint.find(".boxLogProf table:first td:last").append($span.append(" / " + Lint.Config.MaxPoint + Lint.Config.Unit));
		}
		
		function updateResultRows () {
			var prf_d = profResultSet.checked_data || {};

			/* proofread result */
			for (var i = 0, l = prf_d.length; i < l; i++){
				if ($Lint.find(".boxLogProf table:last .row" + prf_d[i].id).is("tr")) {
					prf_d[i].cmd_type = "update";
				} else {
					prf_d[i].cmd_type = "add";
				}
				Mediator.updateLogRow(prf_d[i]);
			}
		}
		
		function rank (num) {
			if (num >= 100) {
				return "S";
			} else if (num <= 99 && num >= 90) {
				return "A";
			} else if (num <= 89 && num >= 70) {
				return "B";
			} else if (num <= 69 && num >= 50) {
				return "C";
			} else if (num <= 49 && num >= 30) {
				return "D";
			} else if (num <= 29 && num >= 0) {
				return "E";
			} else {
				return "F";
			}
		}
		
		function setRowToggleEvent () {
			var $td;
			$Lint.find(".tblDetail:first tr:gt(0) td").each(function(){
				$td = $(this);
				$td.hover(function(){
					if (!$(this).parent().next().is(".trCodeView")) {
						$(this).parent().children("td").css("background", "#f6f6f6");
					}
				},function(){
					if (!$(this).parent().next().is(".trCodeView")) {
						$(this).parent().children("td").css("background", "#fff");
					}
				});
				$td.mousedown(function(){
					$(this).parent().children("td").css("background", "#eee");
				});
				$td.mouseup(function(){
					$(this).parent().children("td").css("background", "#fafafa");
				});
				$td.click(function(){
					onClickRow($(this).parent());
				});
				$td.css("cursor", "pointer");
			});
		}
		
		function onClickRow ($tr) {
			if ($tr.next().hasClass("trCodeView")) {
				$tr.children().css("background", "#fff");
				$tr.next().remove();
			} else {
				$Lint.find(".tblDetail:first .trCodeView").prev().children().css("background", "#fff")
				$Lint.find(".tblDetail:first .trCodeView").remove();
				$tr.children().css("background", "#ffc");
				var $trCodeView = $("<tr />").attr("class", "trCodeView"),
					col_cnt = $Lint.find(".tblDetail:first tr:first td").length,
					$td = $("<td />").attr("colspan", col_cnt).css({"background":"#ffd", "padding-left":"20px"}),
					$div = $("<div />").css({"font-size":"9px", "text-align":"left"}),
					$h2 = $("<h2 />").text("該当箇所").css({"font-size":"18px","font-weight":"bold"});
				$div.append($h2);

				var marker = new SyntaxManager(),
					id = parseInt($tr.attr("class").replace("row", ""), 10);
				Mediator.mark(marker, id);
				$div.append(marker.getResult());
				$tr.after($trCodeView.append($td.append($div)));
			}
		}
		
		return self;
	}; /* - - - / ScoreBoard - - - */
		
	/* -----------------------
		Proofreader
	----------------------- */
	Lint.Proofreader = function () {
		/* dependency */
		var LogicDB = new Lint.LogicDB(),
			Util = new Lint.Util(),
			LocalStorageHandler = new Lint.LocalStorageHandler();
			
		var	self = {};
		
		self.isForPC 		= false;
		self.isForSP 		= false;
		self.isForM 		= false;
		self.isForIE6 		= false;
		self.isForStudent 	= false;
		self.db 			= [];
		self.result_set 	= {};
		
		self.init = function () {
			var type 		= $Lint.find(".MecaLintSet:checked").val(),
				$setting1 	= $Lint.find("#MecaLintSetIE6"),
				$setting2 	= $Lint.find("#MecaLintSetForStudent");
			
			self.isForPC 		= (type === "pc")	? true : false;
			self.isForSP 		= (type === "sp")	? true : false;
			self.isForM 		= (type === "m")	? true : false;
			self.isForIE6 		= ($setting1.is(":checked")) ? true : false;
			self.isForStudent 	= ($setting2.is(":checked")) ? true : false;
			
			self.db = LogicDB.getDB();
			self.result_set = {
				score: 0,
				checked_data: []
			};
		};
		
		self.proofread = function (callback) {
			$.get(location.href, {}, function(data){
				Lint.rawSource = data;
				scanAll();
				if ($.isFunction(callback)) {
					callback();
				}
			});
		};
		
		self.mark = function (marker, logic_id) {
			var logic = self.db[logic_id-1];
			logic.Check(function(sender, $target){		
				marker.mark($target);
			});
		};
		
		self.updateScore = function () {
			Mediator.updateScore(null, self.result_set);
		};
		
		/* check all logic */
		function scanAll () {
			for (var i = 0, l = self.db.length; i < l; i ++) {
				if (shouldScan(self.db[i])) {
					self.db[i].Check(countUp);
				}
			}
		}
		
		function countUp (args) {
			self.result_set.score += args.score;
			var saved_dict = Util.getDictById(args.id, self.result_set.checked_data);
			if (saved_dict === null) {
				args.cnt = 1;
				self.result_set.checked_data.push(args);
			} else {
				Util.getDictById(args.id, self.result_set.checked_data).cnt += 1;
			}
			self.updateScore();
		}
		
		function shouldScan (logic) {
			if (self.isForStudent === true) {
				return canScan(logic);
			} else {
				if (logic.for_student !== true) {
					return canScan(logic);
				}
			}
		}
		
		function canScan (logic) {
			if (self.isForPC && logic.check_for.pc) {
				if (!self.isForIE6) {
					if (logic.for_ie6 !== true) {
						return true;
					}
				} else {
					return true;
				}
			} else if (self.isForSP && logic.check_for.sp) {
				return true;
			} else if (self.isForM && logic.check_for.m) {
				return true;
			} else {
				return false;
			}
		}
		
		return self;
	}; /* - - - / Proofreader - - - */
	
	
	/* -----------------------
		LogicDB
	----------------------- */
	Lint.LogicDB = function () {
		/* dependency */
		var Util = new Lint.Util();
		
		var self = {};
		
		/* Logic DB to Proofread */
		self.getDB = function () {

			var logicDB = [
				{
					id 			: 1,
					title 		: "style属性の記述",
					desc 		: "原則的にタグに直接スタイルシートを指定せず、外部ファイルにて指定して下さい。",
					check_for 	: { "pc":true, "sp":true, "m":false },
					for_ie6 	: false,
					for_student : true,
					rank 		: 2,
					ref 		: [{
						title 	: "第61回　「JavaScriptとスタイルシート（２）」",
						url 	: "http://www.openspc2.org/kouza_js/061/index.html"
					}],
					Check: function (pickUp) {
						var me = this,
							cnt = 0,
							matches = Lint.rawSource.match(/<.*?(style=).*?>/g);
						if (matches !== null) {
							var len = matches.length;
							for (var i = 0; i < len; i++ ) {
								if (i <= 100) {
									pickUp(me, {"hint":matches[i]});
								}
							}
						}
					}
				},{
					id 			: 2,
					title 		: "DOCTYPE宣言を先頭に",
					desc 		: "IE6に対応する場合、DOCTYPE宣言が先頭出ないと後方互換モードになってしまいます。",
					check_for 	: { "pc":true, "sp":false, "m":false },
					for_ie6 	: true,
					for_student : false,
					rank 		: 9,
					score 		: -200,
					ref 		: [{
						title 	: "XML宣言でIE6が後方互換モードになる",
						url 	: "http://hajimetedesign.blog77.fc2.com/blog-entry-27.html"
					}],
					Check: function (pickUp) {
						var me = this;
						if (Lint.rawSource.indexOf("<!DOCTYPE") > 1) {
							pickUp(me, {"hint":Lint.rawSource.split(/\x0D\x0A|\x0D|\x0A/)[0]});
						}
					}
				},{
					id 			: 3,
					title 		: "imgタグにalt属性を設定",
					desc 		: "imgタグにはalt属性に代替テキストを設定する必要があります。",
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 2,
					ref 		: [{
						title 	: "imgタグにおけるaltの使い方について",
						url 	: "http://www.kanzaki.com/docs/html/htminfo-alt.html"
					}],
					Check: function (pickUp) {
						var me = this,
							cnt = 0;
						$("img").each(function(){
							if (cnt <= 100) {
								if (Util.isAncestor("MecaLint", this) === false) {
									if ($(this).attr("alt") === "" || typeof $(this).attr("alt") === "undefined") {
										pickUp(me, $(this));
										cnt ++;
									}	
								}
							}
						});
					}
				},{
					id 			: 4,
					title 		: "head要素内のContent-Type宣言",
					desc 		: 'head要素開始タグ直後に<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />と記述して下さい。',
					check_for 	: { "pc":true, "sp":false, "m":true },
					for_ie6 	: false,
					for_student : true,
					rank 		: 1,
					ref 		: [{
						title 	: "<META>その文書に関する情報（メタ情報）を指定する",
						url 	: "http://www.htmq.com/html/meta.shtml"
					}],
					Check: function (pickUp) {
						var me = this,
							$first = $("head").children(":first"); 
						if ($first.get(0).tagName.match(/meta/i) === null || $first.attr("http-equiv") !== "Content-Type" || $first.attr("content") !== "text/html; charset=utf-8") {
							pickUp(me, $first);
						}
					}
				},{
					id 			: 5,
					title 		: "target属性への_blankの指定",
					desc 		: 'a要素にtarget="_blank"を指定する場合、(meca.jsを使用している場合は)class="external"を指定してください。',
					check_for 	: { "pc":true, "sp":true, "m":false },
					for_ie6 	: false,
					for_student : false,
					rank 		: 2,
					ref 		: [{
						title 	: "meca.js",
						url 	: "http://webtech-walker.com/meca/"
					}],
					Check: function (pickUp) {
						var me = this; 
						$("a").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								if ($(this).attr("target") !== undefined && $(this).attr("target").indexOf("blank") > -1) {
									pickUp(me, $(this));
								}
							}
						});
					}
				},{
					id 			: 6,
					title 		: "href属性は絶対パスで指定",
					desc 		: "a要素のhref属性は絶対パスで指定してください。",
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 3,
					ref 		: [{
						title 	: "絶対パスと相対パス",
						url 	: "http://masaboo.cside.com/new_html1/ht_67.htm"
					}],
					Check: function (pickUp) {
						var me = this,
							cnt = 0;
						$("a").each(function(){
							if (cnt <= 100) {
								if (Util.isAncestor("MecaLint", this) === false) {
									var txt = $(this).attr("href");
									if (txt !== undefined && txt.indexOf("http") !== 0 && txt.indexOf("#") !== 0 && txt.indexOf("/") !== 0) {
										pickUp(me, $(this));
										cnt ++;
									}
								}
							}
						});
					}
				},{
					id 			: 7,
					title 		: "id,class名は小文字キャメルケースで",
					desc 		: 'id,class名は小文字キャメルケースで(hogeHogeのように)指定してください。',
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : true,
					rank 		: 1,
					ref 		: [],
					Check: function (pickUp) {
						var me = this,
							cnt = 0; 
						$("*").each(function(){
							if (cnt <= 100) {
								if (Util.isAncestor("MecaLint", this) === false) {
									var strid = $(this).attr("id"),
										strClass = $(this).attr("class");
									if (
										strid.indexOf("-") > -1 ||
										strid.indexOf("_") > -1 ||
										strid.substring(0, 1).match(/^[A-Z].*/g) ||
										strid.match(/\s[A-Z].*/g) ||
										strClass.indexOf("-") > -1 ||
										strClass.indexOf("_") > -1 ||
										strClass.substring(0, 1).match(/^[A-Z].*/g) ||
										strClass.match(/\s[A-Z].*/g)
									) {
										pickUp(me, $(this));
										cnt ++;
									}
								}
							}
						});
					}
				},{
					id 			: 8,
					title　		: "id、class名の先頭は数字以外",
					desc　		: 'id、class名の先頭に数字を使うことは出来ません。別の名前に設定しなおす必要があります。',
					check_for　	:　{ "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank　		:　4,
					ref　		:　[{
						title 	: "【CSS】class 名や id 名につかっちゃいけない文字",
						url 	: "http://blog.yuu.noor.jp/?eid=1032986"
					}],
					Check: function (pickUp) {
						var me = this; 
						$("*").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								var strid = $(this).attr("id"),
									strClass = $(this).attr("class");
								if (strid.substring(0, 1).match(/^[0-9].*/g) || strClass.substring(0, 1).match(/^[0-9].*/g)) {
									pickUp(me, $(this));
								}
							}
						});
					}
				},{
					id　			: 9,
					title　		: "要素名、属性名は全て小文字",
					desc　		: '可読性向上のため要素名、属性名は全て小文字で記述してください(例：DIV⇒div)。',
					check_for　	:　{ "pc":true, "sp":true, "m":true },
					for_ie6　	: false,
					for_student : false,
					rank　		:　1,
					ref:[],
					Check: function (pickUp) {
						var me = this,
							matches = Lint.rawSource.match(/<[A-Z]* .*>/g);
						if (matches !== null) {
							for (var i = 0; i < matches.length; i++) {
								pickUp(me, {"hint":matches[i]});
							}
						}
					}
				},{
					id 			: 10,
					title 		: "タイトル要素が空です",
					desc 		: 'タイトル要素はそのページのタイトルを必ず記述してください。',
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 8,
					score 		: -100,
					ref 		: [{
						title 	: "title要素",
						url 	: "http://w3g.jp/xhtml/dic/head_title"
					}],
					Check: function (pickUp) {
						var me = this;
						if ($("title").length === 0 || $("title").text() === "") {
							pickUp(me, $("title"));
						}
					}
				},{
					id 			: 11,
					title 		: "タグの入れ子が深い箇所があります",
					desc 		: 'タグの入れ子が8階層以上の深い箇所があります。より単純でメンテナンスのしやすいように設計を見直してください。',
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 2,
					ref 		:[],
					Check: function (pickUp) {
						var me = this;
						$("body > *").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								if(getDepth($(this)) >= 8) {
									pickUp(me, $(this));
								}
							}
						});
						function getDepth($node){
							if ($node.children().length > 0) {
								var deepest = 0;
								$node.children().each(function(){
									var d = getDepth($(this));
									if (d > deepest) {
										deepest = d;
									}
								});
								return deepest + 1;
							} else {
								return 1;
							}
						}
					}
				},{
					id 			: 12,
					title 		: "CSSの外部化はできません",
					desc 		: 'docomoはCSSを外部に設定することができません。CSSはHTMLに直接記述して下さい。',
					check_for 	: { "pc":false, "sp":false, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 7,
					score 		: -40,
					ref 		: [{
						title 	: "3キャリア共通携帯サイト作り方",
						url 	: "http://adsense.wakal.net/177"
					}],
					Check: function (pickUp) {
						var me = this;
						$("link").each(function(){
							pickUp(me, $(this));
						});
					}
				},{
					id 			: 13,
					title 		: "携帯サイトはShift-JISで",
					desc 		: '携帯サイトのmeta要素のcharset属性にはShift-JISを指定して下さい。ファイルのフォーマットも同様にShift-JISで保存して下さい。',
					check_for 	: { "pc":false, "sp":false, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 8,
					score 		: -70,
					ref 		: [{
						title 	: "携帯サイトをUTF-8で出力するかShift_JISで出力するか",
						url 	: "http://blog.fkoji.com/2008/09211552.html"
					}],
					Check: function (pickUp) {
						var me = this;
						$("meta").each(function(){
							if ($(this).attr("http-equiv") !== undefined && $(this).attr("content").toLowerCase().indexOf("shift") === -1) {
								pickUp(me, $(this));
							} 
						});
					}
				},{
					id 			: 14,
					title 		: "viewportの設定",
					desc 		: 'スマホサイトは必ずviewportの設定を行って下さい。',
					check_for 	: { "pc":false, "sp":true, "m":false },
					for_ie6 	: false,
					for_student : false,
					rank 		: 8,
					score 		: -40,
					ref 		: [{
						title: "Viewportとは？",
						url:"http://ipn3g.com/web/study3.html"
					}],
					Check: function (pickUp) {
						var me = this;
						if ($("meta[name='viewport']").length === 0) {
							pickUp(me, $("head"));
						}
					}
				},{
					id 			: 15,
					title 		: "要素に重複したclass属性の指定",
					desc 		: 'class属性が2つ記述されているようです(<hoge class="c1" class="c2" />は×。正しくは<hoge class="c1 c2" />)。',
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 6,
					score 		: -10,
					ref:[{
						title 	: "タグに複数のクラスを指定する",
						url 	: "http://www.openspc2.org/reibun/css/basic/012/"
					}],
					Check: function (pickUp) {
						var me = this;
						/* innerHTMLだと2個目以降のclassが無視されたものが返される */
						var matches = Lint.rawSource.match(/<[^<^>]*class=[^<^>]*class=[^<^>]*>/g);
						if (matches !== null) {
							for (var i = 0; i < matches.length; i++) {
								pickUp(me, {"hint":matches[i]});
							}
						}
					}
				},{
					id 			: 16,
					title　		: "a要素href属性にメタ文字&が使用されています。",
					desc　		: 'メタ文字&は &amp;と書かなければなりません。',
					check_for　	:　{ "pc":true, "sp":true, "m":true },
					for_ie6　	: false,
					for_student : false,
					rank　		:　4,
					ref:[{
						title 	: "対策遅らせるHTMLエンコーディングの「神話」",
						url 	: "http://itpro.nikkeibp.co.jp/article/COLUMN/20070409/267808/"
					}],
					Check: function (pickUp) {
						var me = this;
						/* innerHtmlなどでは、&amp;がすでに&と評価されてしまっているため、非同期で文字列として再ロードする必要がある */
						var data = $("body").html();
						var a_tags = Lint.rawSource.match(/<a.*href=".*">/g),
							matches;
						if (a_tags !== null) {
							for (var i = 0; i < a_tags.length; i++) {
								a_tags[i] = a_tags[i].replaceAll("&#39;", "").replaceAll("&quot;", "").replaceAll("&amp;", "").replaceAll("&lt;", "").replaceAll("&gt;", "");
								matches = a_tags[i].match(/&/g);
								if (matches !== null) {
									for (var j = 0; j < matches.length; j++) {
										pickUp(me, {"hint":a_tags[i]});
									}
								}
							}
						}
					}
				},{
					id 			: 17,
					title 		: "コメントはboxの内側に",
					desc 		: 'floatさせたboxとboxの間にコメントを書くと、IE6で表示崩れを起こす可能性があります。コメントはboxの内側に記述してください(例：＜!-- /.box01 --＞＜/div＞)。',
					check_for 	: { "pc":true, "sp":false, "m":false },
					for_ie6 	: true,
					for_student : false,
					rank 		: 6,
					ref 		: [{
						title 	: "ie6でテキストが複製されboxからはみ出るバグ",
						url 	: "http://blog.iii-design.biz/web/01101346.html"
					}],
					Check: function (pickUp) {
						var me = this,
							checked_list = [];
						
						$("*").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								if ($(this).css("float") !== "" && checked_list.indexOf($(this).parent().get(0)) === -1) {
									var text = $(this).parent().html(),
										$mark_target = $(this),
										j = $(text);
									checked_list.push($(this).parent().get(0));
									j.each(function(idx){
									  if (this.nodeType === 8) {
											if (isSiblingFloating(this, "prev") && isSiblingFloating(this, "next")) {
												pickUp(me, $mark_target);
											}
										}
									});
								}
							}
						});
						
						function isSiblingFloating (obj, direction) {
							var obj = (direction === "prev") ? obj.previousSibling: obj.nextSibling; 
							if (obj !== null) {
								if (obj.nodeType === 3) {
									/* コメントノードの場合再帰 */
									return isSiblingFloating(obj);
								} else {
									var fl = $(obj).css("float");
									if (fl === "left" || fl === "right") {
										return true;
									}
									return false;
								}
							} else {
								return false;
							}
						}
					}
				},{
					id 			: 18,
					title 		: "携帯サイトは半角カタカナで",
					desc 		: '携帯サイトでカタカナを記述する場合、半角カタカナで記述して下さい。',
					check_for 	: { "pc":false, "sp":false, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 0,
					ref:[{
						title 	: "半角カタカナ",
						url 	: "http://mobile.s275.com/file/001664.shtml"
					}],
					Check: function (pickUp) {
						var me = this,
							all_text = Util.textAll(),
							matches = all_text.match(/[ア-ン０-９Ａ-ｚー]/g);
						for (var i = 0; i < matches.length; i++) {
							pickUp(me, {"hint":matches[i]});
						}
					}
				
				},{
					id 			: 19,
					title 		: "IE6はmin-widthなど非対応です",
					desc 		: 'IE6はmin-width、min-height、max-width、max-heightをサポートしていません。これらのプロパティを使用しないか、対応策を検討して下さい。',
					check_for 	: { "pc":true, "sp":false, "m":false },
					for_ie6 	: true,
					for_student : false,
					rank 		: 5,
					ref 		: [{
						title 	: "min-width、min-height、max-width、max-heightをIE6でも実装する方法",
						url 	: "http://www.css-lecture.com/log/css/038.html"
					}],
					Check: function (pickUp) {
						var me = this;
						$("*").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								if ($(this).css("min-width") !== "0px" || $(this).css("min-height") !== "0px" || $(this).css("max-width") !== "none" || $(this).css("max-height") !== "none") {
									pickUp(me, $(this));
								}
							}
						});
					}
				},{
					id 			: 20,
					title 		: "IE6ではpng画像にpngfix",
					desc 		: 'IE6はPNG-24形式のファイルをきれいに表示できないので、meca.jsのpngfixを使うなり、PNG-8で書き出すなりしてください。',
					check_for 	: { "pc":true, "sp":false, "m":false },
					for_ie6 	: true,
					for_student : false,
					rank 		: 5,
					ref 		: [{
						title 	: "meca.js",
						url 	: "http://webtech-walker.com/meca/"
					}],
					Check: function (pickUp) {
						var me = this;
						$("img").each(function(){
							if (Util.isAncestor("MecaLint", this) === false) {
								var src = $(this).attr("src"),
									cls = $(this).attr("class");
								if(src !== undefined && cls !== undefined && src.indexOf(".png") > -1 && cls.indexOf("pngfix") === -1) {
									pickUp(me, $(this));
								}
							}
						});
					}
				},{
					id 			: 21,
					title 		: "不要なコメントは削除してください",
					desc 		: '一時的にコメントアウトしているタグなどは、納品前に削除してください。',
					check_for 	: { "pc":true, "sp":true, "m":true },
					for_ie6 	: false,
					for_student : false,
					rank 		: 5,
					ref 		: [],
					Check: function (pickUp) {
						var me = this;
						var matches1 = Lint.rawSource.match(/<!--([\n\r]|.)*?(-->)/mg),
							matches2;
						if (matches1 !== null) {
							var $innerComment;
							for (var i = 0; i < matches1.length; i++) {
								try {
									matches2 = matches1[i].replace("<!--", "").replace("-->", "");
									matches2 = matches2.match(/.*?<([\n\r]|.)*>/mg);
									if (matches2 !== null) {
										pickUp(me, {"hint":matches2[0]});										
									}
								} catch (e) {
									/* deserve to be left */
								}
							}
						}
					}
				}
			];
			logicDB = setScore(logicDB);
			
			return logicDB;
		};
		
		function setScore (db) {
			for (var i = 0, l = db.length; i < l; i++) {
				if (db[i].score === undefined) {
					db[i].score = parseInt(db[i].rank * - Lint.Config.PointRate, 10);
				}
			};
			
			return db;
		};
		
		return self;
	}; /* - - - / LogicDB - - - */
	
	/* -----------------------
		LocalStorageHandler
	----------------------- */
	
	Lint.LocalStorageHandler = function () {
		var self = {};
		
		self.save = function () {
			var parm = {};
			
			parm.ProofreadConfig = {
				type: $Lint.find(".MecaLintSet:checked").val(),
				ie6: $Lint.find("#MecaLintSetIE6").is(":checked"),
				student: $Lint.find("#MecaLintSetForStudent").is(":checked")
			};
			set("parm", parm);
		};
		
		self.load = function () {
			var parm = get("parm");
			if (parm !== null) {
				$Lint.find(".MecaLintSet").val([parm.ProofreadConfig.type]);
				
				if (parm.ProofreadConfig.ie6 === false) {
					$Lint.find("#MecaLintSetIE6").attr("checked", "");
				}
				if (parm.ProofreadConfig.student === false) {
					$Lint.find("#MecaLintSetForStudent").attr("checked", "");
				}
			}
		};
		
		function set (key, obj) {
			localStorage.setItem(key, JSON.stringify(obj));
		}
	
		function get (key) {
			return JSON.parse(localStorage.getItem(key));
		}
	
		function each (fun) {
			try{
				for (var i=0; i<localStorage.length; i++){
					var k = localStorage.key(i);
					fun(k,db.get(k));
				}
			}catch(e){
				for (var key in localStorage){
					if(key === 'key') continue;
					fun(key,db.get(key));
				}
			}
		}
		
		return self;
	};
	
	
	/* -----------------------
		Util
	----------------------- */
	Lint.Util = function () {
		var self = {};
		
		/* true when obj ancestor element has ancestor_id */
		self.isAncestor = function (ancestor_id, obj) {
			var target = $(obj);
			if (target.attr("id") === ancestor_id) {
				return true;
			}
			if (target.parents("#" + ancestor_id).length > 0){
				return true;
			}
			return false;
		};
		
		/* get dictionary(hash, object) by id from dictionary list
			will be refactored to binary search */
		self.getDictById = function (id, list) {
			for (var i = 0, l = list.length; i < l; i++) {
				if (list[i].id === id) {
					return list[i];
				}
			}
			return null;
		};
		
		self.getBrowserHeight = function () {
			if (window.innerHeight) {
				return window.innerHeight;
			} else if (document.documentElement && document.documentElement.clientHeight !== 0) {
				return document.documentElement.clientHeight;
			} else if (document.body) {
				return document.body.clientHeight;
			}
			return 0;
		};
		
		self.textAll = function () {
			var cnt_char = 0,
				MecaLint_index = $("body>*").index(document.getElementById("MecaLint"));
			$("body>*:gt(" + MecaLint_index + ")").each(function(){
				cnt_char += $(this).text().replaceAll(" ", "").replaceAll(/\t/g, "").replaceAll("\n", "");
			});
			return cnt_char;
		};
		
		String.prototype.replaceAll = function (org, dest) {
			return this.split(org).join(dest);
		};
		return self;
	}; /* - - - / Util - - - */
	
	
	/* -----------------------
		SyntaxManager
	----------------------- */
	Lint.SyntaxManager = function () {
		var self = {},
			root = "",
			alt_message = "",
			separator = '<p style="font-size:11px;margin:10px 0 10px 0;font-weight:bold;">-----------------</p>';
		
		function init () {
			var $root = getRoot($("body")),
				$body = getRoot($("body")).find("#MecaLint");
				
			root = $root.html()
					.replace($body.html(), "")
					.replace(/<div.*MecaLint"[^<^>]*>[^<^>]*<\/div>/i, "");
			root = escapeHTML(root)
					.replaceAll("&lt;", "<p>&lt;")
					.replaceAll("&gt;", "&gt;</p>");
		}
		
		self.getResult = function () {
			if (alt_message === "") {
				return root.replaceAll(/CHECKEDSYNTAX/g, "");				
			} else {
				return alt_message + separator;
			}
			
		};
		
		self.mark = function ($el) {
			
			if (typeof $el === "object" && $el.hint !== undefined) {
				alt_message += separator;
				alt_message += escapeHTML($el.hint);
				return ;
			}
			var target = $el.get(0).outerHTML.match(/<[^<^>]*>/);
			if (target !== null) {
				target = target[0];
				target = escapeHTML(target);
				if(root.indexOf(target) > -1) {
					var start_index = root.indexOf(target),
						end_index 	= start_index + target.length,
						target 		= root.substring(start_index, end_index - 1) + "CHECKEDSYNTAX" + root.substring(end_index - 1, end_index),
						wrapped 	= '<span style="color:#f00;font-weight:bold;font-size:15px;">' + target + "</span>",
						foward_str 	= root.substring(0, start_index),
						latter_str 	= root.substring(end_index, root.length);
					
					root = foward_str + wrapped + latter_str;  
					
				}
			}
		};

		function getRoot ($el) {
			return ($el.parent().length > 0) ? getRoot($el.parent()): $el.children() ;
		}
		
		function escapeHTML(text){
		    var replacement = function(word) {
		        var characterReference = {
		            '"':'&quot;',
		            '&':'&amp;',
		            '\'':'&#39;',
		            '<':'&lt;',
		            '>':'&gt;'
		        };
		        return characterReference[word];
		    };
		    return text.replace( /"|&|'|<|>/g, replacement );
		}
		
		init();
		
		return self;
	};
	
	
	/* -----------------------
		rawSource (extend)
	----------------------- */
	
	Lint.rawSource = "";
	
	/* -----------------------
		Config (extend)
	----------------------- */
	Lint.Config = {
		Unit: "点",　/* 単位 */
		MaxPoint: 100, /* 満点 */
		PointRate: 1.2 /* 評価ロジックの重要ランクから減点数値を出すためのレート */
	};
	
	/* -----------------------
		loadScript (extend)
	----------------------- */

	Lint.loadScript = function (path, callback) {
		/* do callback after loading jQuery from CDN */
		var script = document.getElementsByTagName("script")[0],
			newjs = document.createElement("script");
			
		/* for IE */
		newjs.onreadystatechange = function () {
			if (newjs.readyState === "loaded" || newjs.readyState === "complete") {
				newjs.onreadystatechange = null;
				if (typeof callback === "function") {
					callback();
				}
			}
		};
		/* for others */
		newjs.onload = function () {
			if (typeof callback === "function") {
				callback();
			}
		};		
		newjs.src = path;
		script.parentNode.insertBefore(newjs, script);
	};
	
	/* -----------------------
		log (extend)
	----------------------- */
	
	Lint.log = function (label) {
		var env = location.href.indexOf("file:///C:/") > -1 ? 'dev' : 'prod';
        if (env === "prod") {
          return;
        }
        var args = Array.prototype.slice.call(arguments, 1);

        if (!/String/.test(Object.prototype.toString.call(label))) {
            args.unshift(label);
            label = 'Logs for MecaLint';
        }
        if ($.browser.ipad) {
            console.log(label+ ': ' + args.join(','));
        } else {
            args.unshift("[" + label + "]");
            if ($.browser.msie) {
              if( typeof console !== 'undefined' ) {
                console.log(args);
              }
            }
            else {
                console.log.apply(console, args);
            }
        }
	};
	
	/* Run */
	Lint.init();
	
	
})();